//
//  NSString+EV.m
//  EVClub
//
//  Created by sam on 14-8-29.
//  Copyright (c) 2014年 BitRice. All rights reserved.
//

#import "NSString+EV.h"
#import <CommonCrypto/CommonCrypto.h>
#import <CommonCrypto/CommonDigest.h>


@implementation NSString (EV)

- (NSString*)ev_MD5
{
    // Create pointer to the string as UTF8
    const char *ptr = [self UTF8String];
    
    // Create byte array of unsigned chars
    unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH];
    
    // Create 16 bytes MD5 hash value, store in buffer
    CC_MD5(ptr, strlen(ptr), md5Buffer);
    
    // Convert unsigned char buffer to NSString of hex values
    NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
        [output appendFormat:@"%02x",md5Buffer[i]];
    
    return output;
}

-(int) ev_wordsCount {
    int count = 0;
    bool ignored = NO;
    
    for (int i = 0; i < self.length; i++) {
        unichar ch = [self characterAtIndex:i];
        if((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122) || (ch >= 48 && ch <= 57)) {
            if (!ignored) {
                count++;
                ignored = YES;
            }
        } else {
            count++;
            ignored = NO;
        }
    }
    return count;
}

+ (NSString *)ev_encodeURIComponent:(NSString *)str {
    return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)str, NULL, (__bridge CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ", CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)));
}

- (NSString*)ev_URLEncoding
{
    return (NSString*)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)self, NULL, (__bridge CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ", CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)));
}

-(NSString*)ev_URLDecodedString
{
    NSString *decodedString = [[self stringByReplacingOccurrencesOfString:@"+" withString:@" "]stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    return decodedString;
}

-(NSString *)ev_trim
{
    return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}

- (CGFloat)ev_toFloat
{
    CGFloat version   = 0.f;
    NSArray* verArray = [self componentsSeparatedByString:@"."];
    NSInteger j = 0;
    for (NSInteger i = 0; i < verArray.count; ++i) {
        CGFloat val = [verArray[i] floatValue];
        if (i == 0) {
            version = val;
            continue ;
        }
        j += (val?floorf(log10f(val)):0)+1;
        version += val/powf(10, j);
    }
    return version;
}

-(NSString*)ev_unicode
{
    NSString *tempStr = [self description];
    tempStr = [tempStr stringByReplacingOccurrencesOfString:@"\\u" withString:@"\\U"];
    tempStr = [tempStr stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
    tempStr = [[@"\"" stringByAppendingString:tempStr] stringByAppendingString:@"\""];
    NSData *tempData = [tempStr dataUsingEncoding:NSUTF8StringEncoding];
    NSString* returnStr = [NSPropertyListSerialization propertyListFromData:tempData
                                                           mutabilityOption:NSPropertyListImmutable
                                                                     format:NULL
                                                           errorDescription:NULL];
    return returnStr;
}

- (NSString *)ev_stringByRemovingExtraEmptyChar {
    NSMutableString *resultString = [self.ev_trim mutableCopy];
    
    NSRegularExpression *const extraRegexp = [[NSRegularExpression alloc]initWithPattern:@"[\r\n][ \r\n]*[\r\n]" options:NSRegularExpressionCaseInsensitive error:nil];
    [extraRegexp replaceMatchesInString:resultString options:NSMatchingReportProgress range:NSMakeRange(0, resultString.length) withTemplate:@"\r\n"];
    return [resultString copy];
}

-(BOOL)ev_isNotEmptyString {
    return self.length > 0;
}

- (NSString *)ev_stringByRemoveSuffix:(NSString *)suffix {
    if ([self hasSuffix:suffix]) {
        return [self substringToIndex:self.length - suffix.length];
    }
    return self;
}
+ (NSMutableAttributedString *)ev_attributeStrWithHeaderImage:(NSString *)imageName withBounds:(CGRect)rect withString:(NSString *)contentStr
{
	NSTextAttachment *attachment= [[NSTextAttachment alloc] initWithData:nil ofType:nil];
	UIImage *img = [UIImage imageNamed:imageName];
	attachment.image = img;
	attachment.bounds = rect;//CGRectMake(0, -4, 15, 15 );
	NSAttributedString * text = [NSAttributedString attributedStringWithAttachment:attachment];
	NSMutableAttributedString * nameTmp = [[NSMutableAttributedString alloc] initWithAttributedString:text];
	[nameTmp appendAttributedString:[[NSMutableAttributedString alloc] initWithString:contentStr]];
	return nameTmp;
}

+ (NSMutableAttributedString *)ev_attributeStrWithImage:(UIImage *)img withBounds:(CGRect)rect withString:(NSString *)contentStr
{
	NSTextAttachment *attachment= [[NSTextAttachment alloc] initWithData:nil ofType:nil];
	attachment.image = img;
	attachment.bounds = rect;//CGRectMake(0, -4, 15, 15 );
	NSAttributedString * text = [NSAttributedString attributedStringWithAttachment:attachment];
	NSMutableAttributedString * nameTmp = [[NSMutableAttributedString alloc] initWithAttributedString:text];
	[nameTmp appendAttributedString:[[NSMutableAttributedString alloc] initWithString:contentStr]];
	return nameTmp;
}

-(BOOL)ev_intersectsElementString:(NSString *)otherString bySeparator:(NSString *)separator
{
    NSSet *selfSet = [NSSet setWithArray:[self componentsSeparatedByString:separator]];
    NSSet *otherSet = [NSSet setWithArray:[otherString componentsSeparatedByString:separator]];
    return [selfSet intersectsSet:otherSet];
}

-(BOOL)ev_isEqualToElementString:(NSString *)otherString bySeparator:(NSString *)separator
{
    NSSet *selfSet = [NSSet setWithArray:[self componentsSeparatedByString:separator]];
    NSSet *otherSet = [NSSet setWithArray:[otherString componentsSeparatedByString:separator]];
    return [selfSet isEqualToSet:otherSet];
}

-(BOOL)ev_isSubOfElementString:(NSString *)otherString bySeparator:(NSString *)separator
{
    NSSet *selfSet = [NSSet setWithArray:[self componentsSeparatedByString:separator]];
    NSSet *otherSet = [NSSet setWithArray:[otherString componentsSeparatedByString:separator]];
    return [selfSet isSubsetOfSet:otherSet];
}

- (void)ev_enumerateRegexMatches:(NSString *)regex
                      options:(NSRegularExpressionOptions)options
                   usingBlock:(void (^)(NSString *match, NSRange matchRange, BOOL *stop))block {
    if (regex.length == 0 || !block) return;
    NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:nil];
    if (!regex) return;
    [pattern enumerateMatchesInString:self options:kNilOptions range:NSMakeRange(0, self.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
        block([self substringWithRange:result.range], result.range, stop);
    }];
}

- (NSString *)ev_stringByMatching:(NSString *)regex capture:(NSInteger)capture {
    NSRegularExpression *reg = [NSRegularExpression regularExpressionWithPattern:regex options:NSRegularExpressionCaseInsensitive error:nil];
    NSArray *matchs = [reg matchesInString:self options:NSMatchingReportCompletion range:NSMakeRange(0, self.length)];
    if (matchs.count>0) {
        NSTextCheckingResult *match = [matchs firstObject];
        if (capture < match.numberOfRanges) {
            return [self substringWithRange:[match rangeAtIndex:capture]];
        }
    }
    return self;
}


@end

@implementation NSString (EVTagDecoding)

- (NSArray *)ev_tagArray {
    NSMutableArray *resultTagArray = [NSMutableArray array];
    
    NSMutableArray *resultRanges = [NSMutableArray array];
    
    NSRegularExpression *const hashTagRegexp = [[NSRegularExpression alloc]initWithPattern:@"(#[^#\\r\\n]+?#)" options:NSRegularExpressionCaseInsensitive error:nil];
    
    [hashTagRegexp enumerateMatchesInString:self options:NSMatchingReportProgress range:NSMakeRange(0, self.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
        // 检查重复
        for (NSValue *rangeValue in resultRanges){
            if (NSMaxRange(NSIntersectionRange(rangeValue.rangeValue, result.range))>0){
                return;
            }
        }
        
        if (result.range.length > 2) {
            NSString *tag = [self substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)];
            if (![resultTagArray containsObject:tag]) {
                [resultTagArray addObject:tag];
            }
        }
    }];
    
    return [resultTagArray copy];
}

@end

@implementation NSString (EVAdministrative)

+ (NSString *)ev_administrativeStringWithProvince:(NSString *)province city:(NSString *)city district:(NSString *)district splitString:(NSString *)splitString {
    NSMutableArray *administrativeComponents = [NSMutableArray array];
    
    // Workaround:#8386 【iOS 3.5.x】海南省 未写什么市的充电点 。在列表页面会显示0, city值就是0 =.=||
    if (province.length > 1) {
        [administrativeComponents addObject:province];
    }
    if (city.length > 1 && ![administrativeComponents containsObject:city]) {
        [administrativeComponents addObject:city];
    }
    if (district.length > 1 && ![administrativeComponents containsObject:district]) {
        [administrativeComponents addObject:district];
    }
    
    return [administrativeComponents componentsJoinedByString:splitString ?: @" "];
}

@end

@implementation NSNull(EVString)

-(void)forwardInvocation:(NSInvocation *)anInvocation
{
    if([self respondsToSelector:anInvocation.selector]) [super forwardInvocation:anInvocation];
    else
    {
        NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[@"" methodSignatureForSelector:@selector(description)]];
        [inv setTarget:nil];
        [inv setSelector:anInvocation.selector];
        [inv invoke];
    }
}
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
    NSMethodSignature* signature = [super methodSignatureForSelector:selector];
    if (!signature) signature = [self methodSignatureForSelector:@selector(description)];
    return signature;
}

@end
@implementation NSNumber(EVString)

-(void)forwardInvocation:(NSInvocation *)anInvocation
{
    if([self respondsToSelector:anInvocation.selector]) [super forwardInvocation:anInvocation];
    else
    {
        NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[@"" methodSignatureForSelector:@selector(description)]];
        [inv setTarget:nil];
        [inv setSelector:anInvocation.selector];
        [inv invoke];
    }
}
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
    NSMethodSignature* signature = [super methodSignatureForSelector:selector];
    if (!signature) signature = [self methodSignatureForSelector:@selector(description)];
    return signature;
}

@end

@implementation NSString (hmacmd5)

- (NSString *)ev_hmacMD5StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    unsigned char buffer[CC_MD5_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self ev_stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}

- (NSString *)ev_stringFromBytes:(unsigned char *)bytes length:(int)length {
    NSMutableString *strM = [NSMutableString string];
    
    for (int i = 0; i < length; i++) {
        [strM appendFormat:@"%02x", bytes[i]];
    }
    
    return [strM copy];
}
@end
